package com.linzelin.filter;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.linzelin.config.RsaKeyProperties;
import com.linzelin.pojo.SysRole;
import com.linzelin.pojo.SysUser;
import com.linzelin.utils.JwtUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * jwt登录用拦截器
 */
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    private RsaKeyProperties prop;

    /**
     * 注意这里是需要使用构造方法来传参的,不能用自动注入
     */
    public JwtLoginFilter(AuthenticationManager authenticationManager, RsaKeyProperties prop) {
        this.authenticationManager = authenticationManager;
        this.prop = prop;
    }


    /**
     * 这个就是认证成功之后执行的代码了
     * 还有注意这个方法的前缀要改为public
     */
    @Override
    public void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        SysUser user = new SysUser();
        user.setUsername(authResult.getName());
        user.setRoles((List<SysRole>) authResult.getAuthorities());
        //这里是要放入对应的权限角色
        //这里需要强制转化一下
        String token = JwtUtils.generateTokeExpireInMinutes(user, prop.getPrivateKey(), 60 * 24);
        //设置自定义的用户对象,添加私钥加密,设置保存实践为24h
        response.addHeader("Authorization", "Bearer " + token);
        //这里是将对应的内容保存起来
        try {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter writer = response.getWriter();
            Map resultMap = new HashMap();
            resultMap.put("code", HttpServletResponse.SC_OK);
            resultMap.put("msg", "认证通过!");
            writer.write(new ObjectMapper().writeValueAsString(resultMap));
            //将认证成功的通知发送一下
            writer.flush();
            writer.close();
        } catch (Exception outE) {
            System.out.println(outE);
        }
    }

    /**
     * 认证逻辑配置
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse resp) {
        try {
            SysUser sysUser = new ObjectMapper().readValue(req.getInputStream(), SysUser.class);
            //通过获取的请求去获取用户类
            UsernamePasswordAuthenticationToken authRequest =
                    new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword());
            //将这个用户交给这个类去验证
            return this.authenticationManager.authenticate(authRequest);
        } catch (Exception e) {
            /*这下面的其实就是认证失败的操作了*/
            try {
                resp.setContentType("application/json;charset=utf-8");
                resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                PrintWriter writer = resp.getWriter();
                Map resultMap = new HashMap();
                resultMap.put("code", HttpServletResponse.SC_UNAUTHORIZED);
                resultMap.put("msg", "用户名或密码错误");
                writer.write(new ObjectMapper().writeValueAsString(resultMap));
                //将对应的错误提示保存到map中然后输出
                writer.flush();
                writer.close();
            } catch (Exception outE) {
                System.out.println(outE);
            }
            throw new RuntimeException(e);
        }
    }
}
